<

インターネット経由でデータを更新する

ほとんどのアプリでは、インターネット経由でデータを更新する必要があります。 のhttpパッケージはそれをカバーしています!

このレシピでは次の手順を使用します。

  1. を追加します。httpパッケージ。
  2. を使用してインターネット経由でデータを更新します。httpパッケージ。
  3. 応答をカスタム Dart オブジェクトに変換します。
  4. インターネットからデータを取得します。
  5. 既存のものを更新するtitleユーザー入力から。
  6. 応答を更新して画面に表示します。

1.httpパッケージ

追加するには、httpパッケージを依存関係として、 走るflutter pub add:

$ flutter pub add http

インポートするhttpパッケージ。

import 'package:http/http.dart' as http;

2. を使用してインターネット経由でデータを更新するhttpパッケージ

このレシピでは、アルバム タイトルをJSONプレースホルダーを使用してhttp.put()方法。

Future<http.Response> updateAlbum(String title) {
  return http.put(
    Uri.parse('https://jsonplaceholder.typicode.com/albums/1'),
    headers: <String, String>{
      'Content-Type': 'application/json; charset=UTF-8',
    },
    body: jsonEncode(<String, String>{
      'title': title,
    }),
  );
}

http.put()メソッドはFutureが含まれているResponse

  • Futureを操作するためのコア Dart クラスです。 非同期操作。あFutureオブジェクトは可能性を表します 将来のある時点で使用可能になる値またはエラー。
  • http.Responseクラスには、成功したプログラムから受け取ったデータが含まれています httpコール。
  • updateAlbum()メソッドは引数を受け取ります。title、 を更新するためにサーバーに送信されます。Album

3. を変換します。http.Responseカスタム Dart オブジェクトへ

ネットワークリクエストを行うのは簡単ですが、 生のものを扱うFuture<http.Response>あまり便利ではありません。あなたの生活を楽にするために、 を変換しますhttp.ResponseDart オブジェクトに変換します。

アルバムクラスを作成する

まず、Albumからのデータを含むクラス ネットワークリクエスト。これにはファクトリ コンストラクターが含まれています。 を作成しますAlbumJSONから。

JSON を手動で変換することは 1 つのオプションにすぎません。 詳細については、記事全文を参照してください。JSONとシリアル化

class Album {
  final int id;
  final String title;

  const Album({required this.id, required this.title});

  factory Album.fromJson(Map<String, dynamic> json) {
    return Album(
      id: json['id'],
      title: json['title'],
    );
  }
}

変換するhttp.ResponseAlbum

次に、次の手順を使用して、updateAlbum()を返す関数Future<Album>:

  1. レスポンスボディをJSONに変換するMapとともにdart:convertパッケージ。
  2. サーバーがUPDATEDステータス付きの応答 コード 200 を JSON に変換しますMapAlbumを使用してfromJson()ファクトリーメソッド。
  3. サーバーが応答を返さない場合は、UPDATEDで応答します ステータス コード 200 の場合は、例外がスローされます。 (サーバー応答が「404 Not Found」の場合でも、 例外をスローします。戻らないでくださいnull。 調べるときに大事なこと のデータsnapshot、以下に示すように。)
Future<Album> updateAlbum(String title) async {
  final response = await http.put(
    Uri.parse('https://jsonplaceholder.typicode.com/albums/1'),
    headers: <String, String>{
      'Content-Type': 'application/json; charset=UTF-8',
    },
    body: jsonEncode(<String, String>{
      'title': title,
    }),
  );

  if (response.statusCode == 200) {
    // If the server did return a 200 OK response,
    // then parse the JSON.
    return Album.fromJson(jsonDecode(response.body));
  } else {
    // If the server did not return a 200 OK response,
    // then throw an exception.
    throw Exception('Failed to update album.');
  }
}

万歳! これで、アルバムのタイトルを更新する機能ができました。

4. インターネットからデータを取得する

更新する前に、インターネットからデータを取得してください。 完全な例については、を参照してください。データのフェッチレシピ。

Future<Album> fetchAlbum() async {
  final response = await http.get(
    Uri.parse('https://jsonplaceholder.typicode.com/albums/1'),
  );

  if (response.statusCode == 200) {
    // If the server did return a 200 OK response,
    // then parse the JSON.
    return Album.fromJson(jsonDecode(response.body));
  } else {
    // If the server did not return a 200 OK response,
    // then throw an exception.
    throw Exception('Failed to load album');
  }
}

理想的には、この方法を使用して設定します。_futureAlbumその間initState取ってくる インターネットからのデータ。

5. ユーザー入力に基づいて既存のタイトルを更新します。

を作成しますTextFieldタイトルとElevatedButtonサーバー上のデータを更新します。 また、TextEditingControllerに ユーザー入力を読み取るTextField

ときElevatedButton押されて、 の_futureAlbumによって返される値に設定されますupdateAlbum()方法。

Column(
  mainAxisAlignment: MainAxisAlignment.center,
  children: <Widget>[
    Padding(
      padding: const EdgeInsets.all(8),
      child: TextField(
        controller: _controller,
        decoration: const InputDecoration(hintText: 'Enter Title'),
      ),
    ),
    ElevatedButton(
      onPressed: () {
        setState(() {
          _futureAlbum = updateAlbum(_controller.text);
        });
      },
      child: const Text('Update Data'),
    ),
  ],
);

を押すと、データを更新するボタン、ネットワークリクエスト でデータを送信しますTextFieldとしてサーバーに送信されますPOSTリクエスト。 の_futureAlbum変数は次のステップで使用されます。

5. 応答を画面に表示します

データを画面に表示するには、FutureBuilderウィジェット。 のFutureBuilderウィジェットには Flutter が付属しており、 非同期データ ソースの操作が簡単になります。 次の 2 つのパラメータを指定する必要があります。

  1. Future一緒に働きたいと思っています。この場合、 から戻ってきた未来updateAlbum()関数。
  2. builderFlutterに何をレンダリングするかを指示する関数、 の状態に応じてFuture: 読み込み中、 成功かエラーか。

ご了承くださいsnapshot.hasDataのみを返しますtrueいつ スナップショットには null 以外のデータ値が含まれています。 このため、updateAlbum関数は例外をスローする必要があります 「404 Not Found」サーバー応答の場合でも同様です。 もしもupdateAlbum戻り値nullそれからCircularProgressIndicator無限に表示されます。

FutureBuilder<Album>(
  future: _futureAlbum,
  builder: (context, snapshot) {
    if (snapshot.hasData) {
      return Text(snapshot.data!.title);
    } else if (snapshot.hasError) {
      return Text('${snapshot.error}');
    }

    return const CircularProgressIndicator();
  },
);

完全な例

import 'dart:async';
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

Future<Album> fetchAlbum() async {
  final response = await http.get(
    Uri.parse('https://jsonplaceholder.typicode.com/albums/1'),
  );

  if (response.statusCode == 200) {
    // If the server did return a 200 OK response,
    // then parse the JSON.
    return Album.fromJson(jsonDecode(response.body));
  } else {
    // If the server did not return a 200 OK response,
    // then throw an exception.
    throw Exception('Failed to load album');
  }
}

Future<Album> updateAlbum(String title) async {
  final response = await http.put(
    Uri.parse('https://jsonplaceholder.typicode.com/albums/1'),
    headers: <String, String>{
      'Content-Type': 'application/json; charset=UTF-8',
    },
    body: jsonEncode(<String, String>{
      'title': title,
    }),
  );

  if (response.statusCode == 200) {
    // If the server did return a 200 OK response,
    // then parse the JSON.
    return Album.fromJson(jsonDecode(response.body));
  } else {
    // If the server did not return a 200 OK response,
    // then throw an exception.
    throw Exception('Failed to update album.');
  }
}

class Album {
  final int id;
  final String title;

  const Album({required this.id, required this.title});

  factory Album.fromJson(Map<String, dynamic> json) {
    return Album(
      id: json['id'],
      title: json['title'],
    );
  }
}

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() {
    return _MyAppState();
  }
}

class _MyAppState extends State<MyApp> {
  final TextEditingController _controller = TextEditingController();
  late Future<Album> _futureAlbum;

  @override
  void initState() {
    super.initState();
    _futureAlbum = fetchAlbum();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Update Data Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Update Data Example'),
        ),
        body: Container(
          alignment: Alignment.center,
          padding: const EdgeInsets.all(8),
          child: FutureBuilder<Album>(
            future: _futureAlbum,
            builder: (context, snapshot) {
              if (snapshot.connectionState == ConnectionState.done) {
                if (snapshot.hasData) {
                  return Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      Text(snapshot.data!.title),
                      TextField(
                        controller: _controller,
                        decoration: const InputDecoration(
                          hintText: 'Enter Title',
                        ),
                      ),
                      ElevatedButton(
                        onPressed: () {
                          setState(() {
                            _futureAlbum = updateAlbum(_controller.text);
                          });
                        },
                        child: const Text('Update Data'),
                      ),
                    ],
                  );
                } else if (snapshot.hasError) {
                  return Text('${snapshot.error}');
                }
              }

              return const CircularProgressIndicator();
            },
          ),
        ),
      ),
    );
  }
}